package com.fingard.dsp.bank.directbank.icbc02;

import cn.com.icbc.CMS.commontools.TranslationTool;
import cn.com.infosec.icbc.ReturnValue;
import cn.com.infosec.util.Base64;
import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directConfig.SalaryConfig;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.bank.directbank.chinapay01.util.SecureUtil;
import com.fingard.dsp.bank.directbank.icbc02.bankUtil.AuthSSLProtocolSocketFactory;
import com.fingard.dsp.bank.reqrespobj.single.detail.ReqPayRecDetail;
import com.fingard.dsp.salaryset.SalaryDecrypt;
import com.fingard.io.FileHelper;
import com.fingard.net.*;
import com.fingard.text.Base64Helper;
import com.fingard.text.StringHelper;
import com.fingard.util.BijectionHashMap;
import com.fingard.util.secret.salary.FieldHiddenUtil;
import com.fingard.xml.XElement;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.sql.Connection;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class ICBC02Base extends DirectBase implements ITcpClient {
    protected String bnkVersion = "0.0.0.1";
    protected String bnkTransCode = "";
    protected String bnkBankCode = "102";
    protected String bnkPackageID = "";
    protected String bnkfSeqno = "";
    private final static String s_p_key = "asdfghjklqwertyuiopzxcvb";
    private final static String s_p_iv = "00000000";
    protected static final BijectionHashMap<String, String> IS_ICBC_MAP = new BijectionHashMap<String, String>();
    protected static final BijectionHashMap<String, String> ELE_BILL_TYPE = new BijectionHashMap<String, String>();

    static {
        IS_ICBC_MAP.put("1", "1");
        IS_ICBC_MAP.put("2", "0");

        ELE_BILL_TYPE.put("1", "AC01"); // 银承
        ELE_BILL_TYPE.put("2", "AC02"); // 商承
    }

    public String getPOSCharset() {
        return getBankConfig().getCharset("GBK", "pos");
    }

    public String antiTransferStr(String p_reqInfo) {
        // 针对工行特殊处理，发送银行前每个XML标签中的特殊字符进行反转义,目前只考虑特殊字符'&','<','>'
        if (p_reqInfo.contains("&amp;")) {
            p_reqInfo = p_reqInfo.replace("&amp;", "&");
        }
        if (p_reqInfo.contains("&lt;")) {
            p_reqInfo = p_reqInfo.replace("&lt;", "<");
        }
        if (p_reqInfo.contains("&gt;")) {
            p_reqInfo = p_reqInfo.replace("&gt;", ">");
        }
        return p_reqInfo;
    }

    protected void writeCommonHeader(XmlTextWriter xmlWriter) throws Exception {
        if (StringHelper.isNullOrEmpty(bnkTransCode)) {
            throw new Exception("未赋值TransCode");
        }
        if (StringHelper.isNullOrEmpty(bnkPackageID)) {
            throw new Exception("未赋值PackageID");
        }
        if (StringHelper.isNullOrEmpty(bnkfSeqno)) {
            throw new Exception("未赋值fSeqno");
        }
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"GBK\"?>");
        xmlWriter.writeStartElement("CMS");
        xmlWriter.writeStartElement("eb");
        xmlWriter.writeStartElement("pub");
        xmlWriter.writeElementString("TransCode", bnkTransCode);
        xmlWriter.writeElementString("CIS", bankFront.org);
        xmlWriter.writeElementString("BankCode", bnkBankCode);
        xmlWriter.writeElementString("ID", bankFront.keyID);
        Date tmpDateNow = new Date();
        xmlWriter.writeElementString("TranDate", Format.Date8Format.format(tmpDateNow));
        xmlWriter.writeElementString("TranTime", Format.Time9Format.format(tmpDateNow));
        xmlWriter.writeElementString("fSeqno", bnkfSeqno);
        xmlWriter.writeEndElement();

        xmlWriter.writeStartElement("in");
    }

    // 新增接口，获取Portno
    protected void writeCommonHeaderForPortno(XmlTextWriter xmlWriter) throws Exception {
        if (StringHelper.isNullOrEmpty(bnkPackageID)) {
            throw new Exception("未赋值PackageID");
        }
        if (StringHelper.isNullOrEmpty(bnkfSeqno)) {
            throw new Exception("未赋值fSeqno");
        }
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"GB2312\"?>");
        xmlWriter.writeStartElement("CMS");
        xmlWriter.writeStartElement("eb");
        xmlWriter.writeStartElement("pub");
        xmlWriter.writeElementString("TransCode", "QPERINF", true);
        xmlWriter.writeElementString("CIS", bankFront.org, true);
        xmlWriter.writeElementString("BankCode", bnkBankCode, true);
        xmlWriter.writeElementString("ID", bankFront.keyID, true);
        Date tmpDateNow = new Date();
        xmlWriter.writeElementString("TranDate", Format.Date8Format.format(tmpDateNow), true);
        xmlWriter.writeElementString("TranTime", Format.Time12Format.format(tmpDateNow), true);
        xmlWriter.writeElementString("fSeqno", bnkfSeqno, true);
        xmlWriter.writeEndElement();

        xmlWriter.writeStartElement("in");
    }

    protected void writeCommonHeader(XmlTextWriter xmlWriter, boolean isFromSalaryDecrypt) throws Exception {
        String key = reqHeader.bankCode + "-" + reqHeader.corporation + "-" + reqHeader.group;
        SalaryConfig salaryConfig = SalaryDecrypt.getSalaryConfig(key);
        if (StringHelper.isNullOrEmpty(bnkTransCode)) {
            throw new Exception("未赋值TransCode");
        }
        if (StringHelper.isNullOrEmpty(bnkPackageID)) {
            throw new Exception("未赋值PackageID");
        }
        if (StringHelper.isNullOrEmpty(bnkfSeqno)) {
            throw new Exception("未赋值fSeqno");
        }
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"GBK\"?>");
        xmlWriter.writeStartElement("CMS");
        xmlWriter.writeStartElement("eb");
        xmlWriter.writeStartElement("pub");
        xmlWriter.writeElementString("TransCode", bnkTransCode);
        if (isFromSalaryDecrypt) {
            xmlWriter.writeElementString("CIS", salaryConfig.org);
        } else {
            xmlWriter.writeElementString("CIS", bankFront.org);
        }
        xmlWriter.writeElementString("BankCode", bnkBankCode);
        if (isFromSalaryDecrypt) {
            xmlWriter.writeElementString("ID", salaryConfig.keyID);
        } else {
            xmlWriter.writeElementString("ID", bankFront.keyID);
        }
        Date tmpDateNow = new Date();
        xmlWriter.writeElementString("TranDate", Format.Date8Format.format(tmpDateNow));
        xmlWriter.writeElementString("TranTime", Format.Time9Format.format(tmpDateNow));
        xmlWriter.writeElementString("fSeqno", bnkfSeqno);
        xmlWriter.writeEndElement();

        xmlWriter.writeStartElement("in");
    }

    protected void writeBatCommonHeader(XmlTextWriter xmlWriter) throws Exception {
        if (StringHelper.isNullOrEmpty(bnkTransCode)) {
            throw new Exception("未赋值TransCode");
        }
        if (StringHelper.isNullOrEmpty(bnkfSeqno)) {
            throw new Exception("未赋值fSeqno");
        }
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"" + getCharset() + "\"?>");
        xmlWriter.writeStartElement("CMS");
        xmlWriter.writeStartElement("eb");
        xmlWriter.writeStartElement("pub");
        xmlWriter.writeElementString("TransCode", bnkTransCode);
        xmlWriter.writeElementString("CIS", bankFront.org);
        xmlWriter.writeElementString("BankCode", bnkBankCode);
        xmlWriter.writeElementString("ID", bankFront.keyID);
        Date tmpDateNow = new Date();
        xmlWriter.writeElementString("TranDate", Format.Date8Format.format(tmpDateNow));
        xmlWriter.writeElementString("TranTime", Format.Time12Format.format(tmpDateNow));
        xmlWriter.writeElementString("fSeqno", bnkfSeqno);
        xmlWriter.writeEndElement();

        xmlWriter.writeStartElement("in");
    }

    protected String getCharset() {
        return getBankConfig().getCharset("GBK");
    }

    protected String getCharset(String pFor) {
        return getBankConfig().getCharset("GBK", pFor);
    }

    protected String[] sendToBank(String p_reqStr) throws Exception {
        return sendToBank(p_reqStr, false);
    }

    protected String[] sendToBank(String p_reqStr, boolean p_doSign) throws Exception {
        // Element rootElement = portReqDoc.getDocumentElement();
        // String bnkfSeqno = DomHelper.getSingleElementInnerText(rootElement,
        // "fSeqno");
        // String bnkTransCode =
        // DomHelper.getSingleElementInnerText(rootElement, "TransCode");
        // String bnkBankCode = DomHelper.getSingleElementInnerText(rootElement,
        // "BankCode");
        String keyHead = reqHeader.bankCode + "-" + reqHeader.corporation + "-" + reqHeader.group;
        SalaryConfig salaryConfig = SalaryDecrypt.getSalaryConfig(keyHead);
        String[] retStr = new String[]{"", ""};
        if (bnkPackageID.length() == 0) {
            throw new Exception("PackageID不能为空");
        }
        if (bnkTransCode.length() == 0) {
            throw new Exception("TransCode不能为空");
        }
        if ((!isNeedHiddleField && StringHelper.isNullOrEmpty(bankFront.org)) || (isNeedHiddleField && StringHelper.isNullOrEmpty(salaryConfig.org))) {
            throw new Exception("CIS不能为空");
        }
        if ((!isNeedHiddleField && StringHelper.isNullOrEmpty(bankFront.keyID)) || (isNeedHiddleField && StringHelper.isNullOrEmpty(salaryConfig.keyID))) {
            throw new Exception("ID不能为空");
        }
        // 是否华润发薪加密
        boolean requestTypeJudgeFromSalary = false;
        String requestType = getBankConfig().getValueAsString("requestType");
        boolean enableTrust = getBankConfig().getValueAsBool("enableTrust");
        WriteBankLogLn("是否启动工行通信层公钥进行通信: " + enableTrust);
        if (isNeedHiddleField) {
            requestType = "nonc";
            // 华润发薪的证书信息与客户信息取自SalaryDecrypt.xml
            requestTypeJudgeFromSalary = true;
        }
        if (StringHelper.hasAnyChar(requestType)) {
            WriteBankLogLn("requestType:" + requestType);
        }

        Date tmpDateNow = new Date();
        String charsetName = getCharset();
        String tmpReqData = "";
        if (p_doSign) {
            String[] tmpSignStr = new String[2];
            tmpSignStr[0] = "";
            tmpSignStr[1] = "";
            if ("socket".equalsIgnoreCase(requestType)) {
                isTransferChunked = false;
                WriteBankLogLn("2.提交签名的地址：" + bankFront.serverIP + ":" + bankFront.signPort);
                TcpPortClient tmpClient = new TcpPortClient(bankFront.serverIP, Integer.parseInt(bankFront.signPort), this);
                tmpClient.setContentStartIndex(-1);
                byte[] signBodyBytes = p_reqStr.getBytes(charsetName);
                if (signBodyBytes.length < 10240) {// 10k
                    tmpClient.timeoutMil = this.getReadTimeout(5);// 5秒
                } else if (signBodyBytes.length < 51200) {// 50k
                    tmpClient.timeoutMil = this.getReadTimeout(8);// 8秒
                } else {
                    tmpClient.timeoutMil = this.getReadTimeout(20);// 20秒
                }
                StringBuilder sb = new StringBuilder();
                sb.append("POST / HTTP/1.1\r\n");
                sb.append("Content-Type: INFOSEC_SIGN/1.0\r\n");
                sb.append("Host: " + bankFront.serverIP + ":" + bankFront.signPort + "\r\n");
                sb.append("Connection: close\r\n");
                sb.append("Content-Length: " + signBodyBytes.length + "\r\n");
                sb.append("\r\n");
                String signHeadStr = sb.toString();
                if (isNeedHiddleField) {
                    WriteBankLogLn("2.提交签名的报文：\r\n" + signHeadStr + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                } else {
                    if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                        WriteBankLogLn("2.发送银行的明文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                    } else {
                        WriteBankLogLn("2.提交签名的报文：\r\n" + signHeadStr + p_reqStr);
                    }
                }

                byte[] tmpSignHdBytes = signHeadStr.getBytes(charsetName);
                TcpReceiver tmpReceiver;
                if (signBodyBytes.length < 51200) {// 小于50K
                    byte[] tmpUnionInfo = new byte[tmpSignHdBytes.length + signBodyBytes.length];// 一次性分配内存
                    System.arraycopy(tmpSignHdBytes, 0, tmpUnionInfo, 0, tmpSignHdBytes.length);
                    System.arraycopy(signBodyBytes, 0, tmpUnionInfo, tmpSignHdBytes.length, signBodyBytes.length);
                    tmpReceiver = tmpClient.sendMessage(tmpUnionInfo);
                } else {
                    tmpReceiver = tmpClient.sendMessage(tmpSignHdBytes, signBodyBytes);
                }

                tmpSignStr[0] = tmpReceiver.connState;
                if (ConnState.FAIL.equals(tmpSignStr[0])) {
                    tmpSignStr[1] = tmpReceiver.getConnMsg();
                } else {
                    if (isTransferChunked) {
                        tmpSignStr[1] = getStrFromChunkedBytes(tmpReceiver);
                    } else {
                        tmpSignStr[1] = new String(tmpReceiver.recBytes, 0, tmpReceiver.readedLength, charsetName);
                    }
                    if (!tmpReceiver.isCompleted) {
                        WriteBankLogLn(tmpReceiver.getConnMsg());
                    }
                }
            } else if ("nonc".equalsIgnoreCase(requestType)) {
                // 企业数据层私钥文件
                byte[] key = TranslationTool.readFile(getBankConfig().getValueAsString("key"));
                // 企业数据层私钥密码
                char[] passWord = getBankConfig().getValueAsString("keypass").toCharArray();
                // 需要签名：企业私钥进行签名
                // if (p_doSign){//需要签名做以下操作，否则放明文
                String length = String.valueOf(p_reqStr.length());
                if (length.length() <= 10) {
                    length = ("0000000000").substring(0, 10 - length.length()) + length;// 长度补齐10位，左补0
                }
                if (isNeedHiddleField) {
                    WriteBankLogLn("2.提交签名的报文：" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                } else {
                    if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                        WriteBankLogLn("2.提交签名的报文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                    } else {
                        WriteBankLogLn("2.提交签名的报文：\r\n" + p_reqStr);
                    }
                }
                byte[] bcrymess = ReturnValue.sign(p_reqStr.getBytes(charsetName), p_reqStr.getBytes(charsetName).length, key, passWord);// 这是私钥的密码，请根据实际情况修改
                if (bcrymess == null || bcrymess.length == 0) {
                    tmpSignStr[0] = "-1";
                    tmpSignStr[1] = "私钥加密错误，请检查config文件的key标签和keypass标签的配置是否正确";
                    return tmpSignStr;
                }
                // 数字字符串+明文+“ICBCMP”+ BASE64加密的密文
                tmpReqData = length + p_reqStr + "ICBCCMP" + Base64Helper.getBase64(bcrymess);
                String tmpReqData2 = Base64Helper.getBase64(tmpReqData.getBytes(charsetName));
                tmpReqData = URLEncoder.encode(tmpReqData2, charsetName);
                // }
            } else {
                String tmpAddrSign = "http://" + bankFront.serverIP + ":" + bankFront.signPort;
                WriteBankLogLn("2.提交签名的地址：" + tmpAddrSign);
                if (isNeedHiddleField) {
                    WriteBankLogLn("2.提交签名的报文：" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                } else {
                    if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                        WriteBankLogLn("2.发送银行的明文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                    } else {
                        WriteBankLogLn("2.发送银行的明文：\r\n" + p_reqStr);
                    }
                }

                WebRequest tmpWebRequestSign = new WebRequest(tmpAddrSign);
                tmpWebRequestSign.setLogCode(this.getLogCode());
                tmpWebRequestSign.setConnectTimeout(600000);
                tmpWebRequestSign.setRequestProperty("Content-Type", "INFOSEC_SIGN/1.0");
                tmpWebRequestSign.setRequestProperty("connection", "Close");

                byte[] tmpToSignBytes = p_reqStr.getBytes(charsetName);
                tmpSignStr = tmpWebRequestSign.upload(tmpToSignBytes, charsetName);
            }
            // 非NC模式不需要对签名做处理
            if (!"nonc".equalsIgnoreCase(requestType)) {
                WriteBankLogLn("3.签名返回的结果：" + tmpSignStr[1]);

                if (tmpSignStr[0].equals(ConnState.FAIL)) {
                    return tmpSignStr;
                }
                int tmpStartIndex = tmpSignStr[1].indexOf("<sign>");
                int tmpEndIndex = tmpSignStr[1].lastIndexOf("</sign>");
                if (tmpStartIndex < 0 || tmpEndIndex < 0) {
                    tmpSignStr[0] = ConnState.FAIL;
                    return tmpSignStr;
                }
                tmpReqData = tmpSignStr[1].substring(tmpStartIndex + 6, tmpEndIndex);
                if (tmpReqData.indexOf("\n") >= 0 || tmpReqData.indexOf("\r") >= 0) {
                    tmpReqData = tmpReqData.replace("\n", "").replace("\r", "");
                }
            }

        }
        // 不需要签名
        else {
            if (isNeedHiddleField) {
                WriteBankLogLn("2.发送银行的明文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
            } else {
                if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                    WriteBankLogLn("2.发送银行的明文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                } else {
                    WriteBankLogLn("2.发送银行的明文：\r\n" + p_reqStr);
                }
            }
            if ("nonc".equalsIgnoreCase(requestType)) {
                p_reqStr = Base64Helper.getBase64(p_reqStr, charsetName);
            }
            tmpReqData = URLEncoder.encode(p_reqStr, charsetName);
        }

        String addressSuffix = "/servlet/ICBCCMPAPIReqServlet";
        boolean configurableAddress = getBankConfig().getValueAsBool("configurableAddress");
        if (configurableAddress) {
            addressSuffix = getBankConfig().getValueAsString("addressSuffix");
            if (StringHelper.isNullOrEmpty(addressSuffix)) {
                addressSuffix = "/servlet/ICBCCMPAPIReqServlet";
            }
        }
        // 获取版本号
        String version = getBankConfig().getMapValueByKey("versionMapping", bnkTransCode);
        version = "".equals(version) ? bnkVersion : version;

        String postPage = addressSuffix + "?userID=" + bankFront.keyID + "&PackageID=" + bnkPackageID + "&SendTime=" + Format.DateTime14Format.format(tmpDateNow);
        String tmpToSendInfo = "Version=" + version + "&TransCode=" + bnkTransCode + "&BankCode=" + bnkBankCode + "&GroupCIS=" + bankFront.org + "&ID=" + bankFront.keyID + "&PackageID=" + bnkPackageID + "&Cert=&reqData=" + tmpReqData;

        int setTimeoutMil = 60000;
        if ("7506".equals(this.reqHeader.transType)) {
            setTimeoutMil = this.getReadTimeout(10);
        } else if ("1944".equals(this.reqHeader.transType)) {
            setTimeoutMil = this.getReadTimeout(20);
        } else {
            setTimeoutMil = this.getReadTimeout(60);
        }

        if ("socket".equalsIgnoreCase(requestType)) {
            isTransferChunked = false;
            WriteBankLogLn("2.提交服务的地址：" + bankFront.serverIP + ":" + bankFront.serverPort);
            TcpPortClient tmpClient = new TcpPortClient(bankFront.serverIP, Integer.parseInt(bankFront.serverPort), this);
            tmpClient.setContentStartIndex(-1);
            byte[] sndBodyBytes = tmpToSendInfo.getBytes(charsetName);
            tmpClient.timeoutMil = setTimeoutMil;
            StringBuilder sbHead = new StringBuilder();
            sbHead.append("POST " + postPage + " HTTP/1.1\r\n");
            sbHead.append("User-Agent: Jakarta Commons-HttpClient/3.1\r\n");
            sbHead.append("Host: " + bankFront.serverIP + ":" + bankFront.serverPort + "\r\n");
            sbHead.append("Content-Type: application/x-www-form-urlencoded\r\n");
            sbHead.append("Connection: close\r\n");
            sbHead.append("Content-Length: " + sndBodyBytes.length + "\r\n");
            sbHead.append("\r\n");

            String sndHeadStr = sbHead.toString();
            WriteBankLogLn("2.提交服务的报文：\r\n" + sndHeadStr + tmpToSendInfo);

            byte[] headBytes = sndHeadStr.getBytes(charsetName);
            TcpReceiver tmpReceiver;
            if (sndBodyBytes.length < 204800) {// 小于200K
                byte[] tmpUnionInfo = new byte[headBytes.length + sndBodyBytes.length];// 一次性分配内存
                System.arraycopy(headBytes, 0, tmpUnionInfo, 0, headBytes.length);
                System.arraycopy(sndBodyBytes, 0, tmpUnionInfo, headBytes.length, sndBodyBytes.length);
                tmpReceiver = tmpClient.sendMessage(tmpUnionInfo);
            } else {
                tmpReceiver = tmpClient.sendMessage(headBytes, sndBodyBytes);
            }

            retStr[0] = tmpReceiver.connState;
            if (ConnState.FAIL.equals(retStr[0])) {
                retStr[1] = tmpReceiver.getConnMsg();
            } else {
                // 测试用
                // isTransferChunked=true;
                // tmpReceiver.recBytes =
                // FileHelper.readFileBytes("D:\\getToWork\\14-filesForDevelop\\ICBC02\\7516-chunked-test.txt");
                // tmpReceiver.readedLength = tmpReceiver.recBytes.length;
                // 测试用
                if (isTransferChunked) {
                    retStr[1] = getStrFromChunkedBytes(tmpReceiver);
                } else {
                    retStr[1] = new String(tmpReceiver.recBytes, 0, tmpReceiver.readedLength, charsetName);
                }
                WriteBankLogStep3(retStr[1]);
                if (!tmpReceiver.isCompleted) {
                    WriteBankLogLn(tmpReceiver.getConnMsg());
                }
            }
        } else if ("nonc".equalsIgnoreCase(requestType)) {
            // 读取配置企业数据层公钥文件
            FileInputStream fii = null;
            try {
                fii = new FileInputStream(new File(getBankConfig().getValueAsString("cerfile")));
                byte[] certificate = new byte[fii.available()];
                fii.read(certificate);// 公钥

                String tmpToSendInfo2 = "";
                String tmpAddr = "";
                // 不是华润发薪，并且不启用工行通信层证书
                if (!requestTypeJudgeFromSalary && !enableTrust) {
                    tmpAddr = "https://" + bankFront.serverIP + ":" + bankFront.serverPort + postPage;
                    tmpToSendInfo2 = "Version=" + URLEncoder.encode(version, charsetName) + "&TransCode=" + URLEncoder.encode(bnkTransCode, charsetName) + "&BankCode=" + URLEncoder.encode(bnkBankCode, charsetName) + "&GroupCIS=" + URLEncoder.encode(bankFront.org, charsetName) + "&ID=" + URLEncoder.encode(bankFront.keyID, charsetName) + "&PackageID=" + URLEncoder.encode(bnkPackageID, charsetName) + "&Cert=" + URLEncoder.encode(Base64Helper.getBase64(certificate), charsetName) + "&reqData=" + tmpReqData;
                }
                // 是华润发薪，不启用工行通信证书
                else if (requestTypeJudgeFromSalary && !enableTrust) {
                    tmpAddr = "https://" + salaryConfig.serverIp + ":" + salaryConfig.port + postPage;
                    tmpToSendInfo2 = "Version=" + URLEncoder.encode(version, charsetName) + "&TransCode=" + URLEncoder.encode(bnkTransCode, charsetName) + "&BankCode=" + URLEncoder.encode(bnkBankCode, charsetName) + "&GroupCIS=" + URLEncoder.encode(salaryConfig.org, charsetName) + "&ID=" + URLEncoder.encode(salaryConfig.keyID, charsetName) + "&PackageID=" + URLEncoder.encode(bnkPackageID, charsetName) + "&Cert=" + URLEncoder.encode(Base64Helper.getBase64(certificate), charsetName) + "&reqData=" + tmpReqData;
                }
                // 不是华润发薪，启动工行通信证书
                else if (!requestTypeJudgeFromSalary && enableTrust) {
                    Protocol authhttps;
                    authhttps = new Protocol("https", new AuthSSLProtocolSocketFactory(null, null, new URL("file:///" + getBankConfig().getValueAsString("trust")), null), 8446);
                    // 建立HttpClient，并进行配置
                    HttpClient client = new HttpClient();
                    client.getHostConfiguration().setHost(bankFront.serverIP, Integer.valueOf(bankFront.serverPort), authhttps);
                    if (FGBiz.dspCenter.dspSet.enableProxy) {
                        String proxyIP = FGBiz.dspCenter.dspSet.proxyIP;
                        int proxyPort = Integer.parseInt(FGBiz.dspCenter.dspSet.proxyPort);
                        client.getHostConfiguration().setProxy(proxyIP, proxyPort);
                    }
                    // 创建post方式，为httppost设定参数
                    PostMethod httppost = new PostMethod("/servlet/ICBCCMPAPIReqServlet"); // 定义postmethod

                    httppost.setParameter("Version", version);
                    httppost.setParameter("TransCode", bnkTransCode);
                    httppost.setParameter("BankCode", bnkBankCode);
                    httppost.setParameter("GroupCIS", bankFront.org);
                    httppost.setParameter("ID", bankFront.keyID);
                    httppost.setParameter("PackageID", bnkPackageID);
                    httppost.setParameter("Cert", Base64Helper.getBase64(certificate));
                    httppost.setParameter("reqData", URLDecoder.decode(tmpReqData, getCharset()));// 对报文进行编码编码

                    int re_code = client.executeMethod(httppost);// 执行post

                    if (re_code == HttpStatus.SC_OK) {
                        String s1 = new String(httppost.getResponseBodyAsString());
                        WriteBankLogLn("3.银行返回的报文" + s1);
                        retStr[1] = new String(Base64.decode(s1.split("=", 2)[1]), getCharset());
                        WriteBankLogLn("4.返回报文内容进行base64解密之后的内容" + retStr[1]);
//					 new String(base64Decoder.decodeBuffer(retStr[1]))
                        return retStr;
                    }// 若通讯成功，解码并输出报文
                }
                // 是华润发薪，启动工行证书
                else {
                    Protocol authhttps;
                    authhttps = new Protocol("https", new AuthSSLProtocolSocketFactory(null, null, new URL("file:///" + getBankConfig().getValueAsString("trust")), null), 8446);
                    // String key = reqHeader.bankCode+"-"+reqHeader.corporation
                    // +"-"+reqHeader.group;
                    // SalaryConfig salaryConfig =
                    // SalaryDecrypt.getSalaryConfig(key);
                    // 建立HttpClient，并进行配置
                    HttpClient client = new HttpClient();
                    client.getHostConfiguration().setHost(salaryConfig.serverIp, Integer.valueOf(salaryConfig.port), authhttps);
                    //判断是否启用代理
                    if (FGBiz.dspCenter.dspSet.enableProxy) {
                        String proxyIP = FGBiz.dspCenter.dspSet.proxyIP;
                        int proxyPort = Integer.parseInt(FGBiz.dspCenter.dspSet.proxyPort);
                        client.getHostConfiguration().setProxy(proxyIP, proxyPort);
                    }
                    // 创建post方式，为httppost设定参数
                    PostMethod httppost = new PostMethod("/servlet/ICBCCMPAPIReqServlet"); // 定义postmethod

                    httppost.setParameter("Version", version);
                    httppost.setParameter("TransCode", bnkTransCode);
                    httppost.setParameter("BankCode", bnkBankCode);
                    httppost.setParameter("GroupCIS", salaryConfig.org);
                    httppost.setParameter("ID", salaryConfig.keyID);
                    httppost.setParameter("PackageID", bnkPackageID);
                    httppost.setParameter("Cert", Base64Helper.getBase64(certificate));
                    httppost.setParameter("reqData", URLDecoder.decode(tmpReqData, getCharset()));// 对报文进行编码编码

                    int re_code = client.executeMethod(httppost);// 执行post

                    if (re_code == HttpStatus.SC_OK) {
                        String s1 = new String(httppost.getResponseBodyAsString());
                        retStr[1] = new String(Base64.decode(s1.split("=", 2)[1]), getCharset());
                        if (isNeedHiddleField) {
                            WriteBankLogLn("3.银行返回的报文" + FieldHiddenUtil.amountHiddle(retStr[1], new String[]{"TotalAmt", "PayAmt"}));
                        } else {
                            if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                                WriteBankLogLn("2.发送银行的明文：\r\n" + FieldHiddenUtil.amountHiddle(p_reqStr, new String[]{"TotalAmt", "PayAmt"}));
                            } else {
                                WriteBankLogLn("3.银行返回的报文" + retStr[1]);// new
                            }                                        // String(base64Decoder.decodeBuffer(retStr[1]))
                        }
                        return retStr;
                    }// 若通讯成功，解码并输出报文
                }
                WriteBankLogLn("2.提交银行的地址：" + tmpAddr);
                if (!isNeedHiddleField) {
                    WriteBankLogStep2(tmpToSendInfo2);
                } else {
                    WriteBankLogStep2(tmpToSendInfo2.substring(0, tmpToSendInfo2.indexOf("&reqData=")) + "...");
                }
                byte[] tmpToWriteBytes = tmpToSendInfo2.getBytes(charsetName);
                // 服务器启动
                // start();
                // 发送请求报文
                WebRequest tmpWebRequest = new WebRequest(tmpAddr);
                tmpWebRequest.setLogCode(this.getLogCode());
                tmpWebRequest.setConnectTimeout(600000);
                tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                // //添加工行通信证书
                // tmpWebRequest.
                retStr = tmpWebRequest.upload(tmpToWriteBytes, charsetName);
                // 如果验证不通过，需要添加工行通讯层公钥验证通讯，则参考myBank01中的方法
                // use the client certificate
                // KeyStore ks = KeyStore.getInstance("PKCS12");
                // ks.load(new FileInputStream(new File(keyStorePath)),
                // keyStorePswd.toCharArray());
                //
                // KeyManagerFactory kmf =
                // KeyManagerFactory.getInstance("SunX509");
                // kmf.init(ks, keyStorePswd.toCharArray());
                // 返回报文处理
                if (!isNeedHiddleField) {
                    WriteBankLogLn("银行返回的内容：" + retStr[1]);
                }
                int index1 = retStr[1].indexOf("reqData=");
                if (retStr[0].length() == 0 && index1 >= 0) {
                    String tmpRetPlain = Base64Helper.getFromBase64(retStr[1].substring(index1 + 8), charsetName);
                    if (tmpRetPlain.contains("ICBCCMP")) {
                        tmpRetPlain = tmpRetPlain.substring(10, tmpRetPlain.indexOf("ICBCCMP"));
                    }
                    // WriteBankLogLn("3.银行返回的明文：\r\n" + tmpRetPlain);

                    retStr[1] = tmpRetPlain;
                }
                // 服务器停止
                // stop();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fii != null) {
                    fii.close();
                }
            }
        } else {
            String tmpAddr = "http://" + bankFront.serverIP + ":" + bankFront.serverPort + postPage;
            WriteBankLogLn("2.提交银行的地址：" + tmpAddr);
            WriteBankLogStep2(tmpToSendInfo);
            byte[] tmpToWriteBytes = tmpToSendInfo.getBytes(charsetName);
            WebRequest tmpWebRequest = new WebRequest(tmpAddr);
            tmpWebRequest.setLogCode(this.getLogCode());
            tmpWebRequest.setConnectTimeout(20000);

            tmpWebRequest.setReadTimeout(setTimeoutMil);

            tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            tmpWebRequest.setRequestProperty("User-agent", "  Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0");
            // tmpWebRequest.setRequestProperty("connection", "Close");

            retStr = tmpWebRequest.upload(tmpToWriteBytes, charsetName);
        }
        if (!"nonc".equalsIgnoreCase(requestType)) {
            // 测试用
            // retStr[0]="";
            // retStr[1] =
            // FileHelper.readFileText("D:\\getToWork\\14-filesForDevelop\\ICBC02\\1944bkBase64.txt",
            // "gbk");
            // 测试用
            int index1 = retStr[1].indexOf("reqData=");
            if (retStr[0].length() == 0 && index1 >= 0) {
                // return tmpRetStr.substring(8);
                String tmpRetPlain = Base64Helper.getFromBase64(retStr[1].substring(index1 + 8), charsetName);
                // boolean enableSalaryDecrypt =
                // getBankConfig().getValueAsBool("enableSalaryDecrypt");
                // if(enableSalaryDecrypt){
                // WriteBankLogLn("3.银行返回的明文：\r\n"+FieldHiddenUtil.amountHiddle(tmpRetPlain,new
                // String[]{"PayAmt"}));
                // }else{
                // WriteBankLogLn("3.银行返回的明文：\r\n"+tmpRetPlain);
                // }
                retStr[1] = tmpRetPlain;
            }
        }
        if (isNeedHiddleField) {
            WriteBankLogLn("3.银行返回的报文" + FieldHiddenUtil.amountHiddle(retStr[1], new String[]{"TotalAmt", "PayAmt"}));
        } else {
            if (getBankConfig().getValueAsBool("useSalaryEncrypt")) {
                WriteBankLogLn("3.银行返回的报文明文:\r\n" + FieldHiddenUtil.amountHiddle(retStr[1], new String[]{"TotalAmt", "PayAmt"}));
            } else {
                WriteBankLogLn("3.银行返回的报文明文:\r\n" + retStr[1]);
            }
        }
        return retStr;
    }

    protected String[] sendToBankForPortno(String sendInfo) throws Exception {
        String charsetStr = getBankConfig().getValueAsString("charset2");
        String[] result = {"", ""};
        /*byte[] tmpUpBytes = sendInfo.getBytes(getCharset());
        String tmpReqData = URLEncoder.encode(tmpUpBytes.toString(), getCharset());*/

/*
        String sendData = "Version=0.0.0.1&TransCode=QPERINF" + "&BankCode=" + bnkBankCode + "&GroupCIS=" + bankFront.org + "&ID=" + bankFront.keyID + "&PackageID=" + bnkPackageID + "&Cert=&reqData=" + tmpReqData;
*/
        String sendData = "Version=0.0.0.1&TransCode=QPERINF" + "&BankCode=" + bnkBankCode + "&GroupCIS=" + bankFront.org + "&ID=" + bankFront.keyID + "&PackageID=" + bnkPackageID + "&Cert=&reqData=" + sendInfo;
        WriteBankLogLn("**************" + sendData);
        byte[] bytes = sendData.getBytes(charsetStr);

        String url = "http://" + bankFront.serverIP + ":" + bankFront.serverPort + "/servlet/ICBCCMPAPIReqServlet?userID=" + bankFront.keyID + "&PackageID=" + bnkPackageID + "&SendTime=" + Format.DateTime14Format.format(new Date());
        WebRequest tmpWebRequest = new WebRequest(url);
        tmpWebRequest.setConnectTimeout(60000);
        tmpWebRequest.setRequestProperty("Method", "POST");
        tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        result = tmpWebRequest.upload(bytes, charsetStr);
        WriteBankLogLn("请求缴费编号银行返回：" + result[1]);
        result[1] = result[1].replace("reqData=", "");
        result[1] = new String(Base64.decode(result[1]), charsetStr);
        WriteBankLogLn("请求缴费编号银行返回base64解密后的内容：" + result[1]);
        return result;
    }

    private String getStrFromChunkedBytes(TcpReceiver p_receiver) throws UnsupportedEncodingException {
        int s_idx = 0;
        for (int i = 0; i < p_receiver.readedLength; i++) {
            if (p_receiver.recBytes[i] == tmpHeadCut1) {
                if (p_receiver.readedLength > (i + 3)) {
                    if (p_receiver.recBytes[i + 1] == tmpHeadCut2 && p_receiver.recBytes[i + 2] == tmpHeadCut1 && p_receiver.recBytes[i + 3] == tmpHeadCut2) {
                        s_idx = i + 4;
                        break;
                    }
                }
            }
        }

        int totalLen = 0;
        int lastIdx = s_idx;
        int offset = lastIdx;
        ArrayList<int[]> listCut = new ArrayList<int[]>(10);
        while (offset < p_receiver.readedLength) {
            if (p_receiver.recBytes[offset] == tmpHeadCut1) {
                if (p_receiver.readedLength > (offset + 1) && p_receiver.recBytes[offset + 1] == tmpHeadCut2) {
                    String stepLen16 = new String(p_receiver.recBytes, lastIdx, offset - lastIdx, getCharset()).trim();
                    int intLen = Integer.parseInt(stepLen16, 16);
                    if (intLen == 0) {
                        break;
                    }
                    int[] forCut = new int[2];
                    forCut[0] = offset + 2;
                    forCut[1] = forCut[0] + intLen;
                    listCut.add(forCut);
                    totalLen += intLen;
                    lastIdx = forCut[1] + 1;
                    offset = lastIdx;
                    continue;
                }
            }
            offset++;
        }
        byte[] resultBytes = new byte[totalLen];
        int cpoffset = 0;
        for (int i = 0; i < listCut.size(); i++) {
            int cplen = listCut.get(i)[1] - listCut.get(i)[0];
            System.arraycopy(p_receiver.recBytes, listCut.get(i)[0], resultBytes, cpoffset, cplen);
            cpoffset += cplen;
        }
        return new String(resultBytes, getCharset());
    }

    // 上送格式为json格式
    protected String[] sendToATS(String jsonData) throws Exception {
        String[] retStr = new String[]{"", ""};
        WriteBankLogLn("2.提交ATS的地址：" + FGBiz.dspCenter.dspSet.receiptPushServerUrl);

        // 发送银行前置
        WebRequest tmpRequest = new WebRequest(FGBiz.dspCenter.dspSet.receiptPushServerUrl);
        tmpRequest.setConnectTimeout(10000);
        tmpRequest.setRequestProperty("connection", "Close");
        tmpRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        String charsetName = getCharset();
        StringBuilder data = new StringBuilder();
        data.append(jsonData);
        WriteBankLogLn("3.推送给ATS的数据" + data.toString());
        byte[] tmpWriteBytes = data.toString().getBytes(charsetName);
        retStr = tmpRequest.upload(tmpWriteBytes, charsetName);
        WriteBankLogLn("4.返回的数据" + retStr[1]);

        return retStr;
    }

    protected static boolean isActiveRetCode(String retCode) {
        if (retCode != null) {
            if (retCode.equals("") || retCode.equals("0") || retCode.equals("00000")) {
                return true;
            }
        }
        return false;
    }

    protected boolean isMCardAcc(String accNo) {
        if (accNo.contains("-")) {
            if (accNo.split("-").length == 2 && accNo.split("-")[1].length() == 9) {
                return true;
            }
            return false;
        }
        return false;
    }

    protected XElement convertPayRecDetailToBankXElement(ReqPayRecDetail p_atsDetail, int p_seqIndex, String reqBatchNo, String defautCity) throws Exception {
        XElement tmpXElement = new XElement("rd", "");
        tmpXElement.addChild(new XElement("iSeqno", String.valueOf(p_seqIndex)));
        tmpXElement.addChild(new XElement("ReimburseNo", ""));
        tmpXElement.addChild(new XElement("ReimburseNum", ""));
        tmpXElement.addChild(new XElement("StartDate", ""));
        tmpXElement.addChild(new XElement("StartTime", ""));
        // PayType 1：加急 2：普通
        if (!StringHelper.isNullOrEmpty(p_atsDetail.paySpd) && p_atsDetail.paySpd.equals("1")) {
            tmpXElement.addChild(new XElement("PayType", "1"));
        } else {
            tmpXElement.addChild(new XElement("PayType", "2"));
        }

        //付方账户
        if (getBankConfig().getValueAsBool("isMCardAcc") && isMCardAcc(p_atsDetail.payAct) && "1".equals(p_atsDetail.sameBnk)) {
            tmpXElement.addChild(new XElement("MCardNo", p_atsDetail.payAct.split("-")[0]));
            tmpXElement.addChild(new XElement("MCardName", p_atsDetail.payName));
            tmpXElement.addChild(new XElement("PaySubNo", p_atsDetail.payAct.split("-")[1]));
        } else {
            tmpXElement.addChild(new XElement("PayAccNo", p_atsDetail.payAct));
            tmpXElement.addChild(new XElement("PayAccNameCN", p_atsDetail.payName));
        }
        tmpXElement.addChild(new XElement("PayAccNameEN", ""));
        //收方账户
        if (getBankConfig().getValueAsBool("isMCardAcc") && isMCardAcc(p_atsDetail.recAct) && "1".equals(p_atsDetail.sameBnk)) {
            tmpXElement.addChild(new XElement("RecAccNo", p_atsDetail.recAct.split("-")[0]));
            tmpXElement.addChild(new XElement("RecSubNo", p_atsDetail.recAct.split("-")[1]));
        } else {
            tmpXElement.addChild(new XElement("RecAccNo", p_atsDetail.recAct));
            tmpXElement.addChild(new XElement("RecAccNameCN", p_atsDetail.recName));
        }
        tmpXElement.addChild(new XElement("RecAccNameEN", ""));
        // 1：系统内 2：系统外
        if (p_atsDetail.sameBnk.equals("1")) {
            tmpXElement.addChild(new XElement("SysIOFlg", "1"));
        } else {
            tmpXElement.addChild(new XElement("SysIOFlg", "2"));
        }
        // 1：同城 2：异地
        if (p_atsDetail.sameCity.equals("1")) {
            tmpXElement.addChild(new XElement("IsSameCity", "1"));
        } else {
            tmpXElement.addChild(new XElement("IsSameCity", "2"));
        }
        if (bnkTransCode.equals("PAYENT")) {
            // CMS/eb/in/rd/Prop 对公对私标志 0：对公账户 1：个人账户"
            // DSP针对对公对私标志的判断统一为，ATS发出的<IsPrivate>为2对公，其它则为对私
            if (p_atsDetail.isPrivate.equals("2")) {
                tmpXElement.addChild(new XElement("Prop", "0"));
            } else {
                tmpXElement.addChild(new XElement("Prop", "1"));
            }
        }
        String tmpRecICBCCode = "";
        /*
         * if(bnkTransCode.equals("PAYPERCOL") ||
         * bnkTransCode.equals("PAYPER")){
         * if(p_atsDetail.sameBnk.equals("1")){//同行 tmpRecICBCCode =
         * p_atsDetail.recArea; } }
         */
        tmpXElement.addChild(new XElement("RecICBCCode", tmpRecICBCCode));
        String tmpRecCityName = "";
        String tmpRecBankNo = "";
        String tmpRecBankName = p_atsDetail.recBankLocation;
        if (!p_atsDetail.sameBnk.equals("1")) {// 跨行
            // RecCityName 收款方所在城市名称 跨行指令此项必输
            tmpRecCityName = p_atsDetail.recAreaName;
            if (StringHelper.hasAnyChar(p_atsDetail.cnapsCode)) {
                tmpRecBankNo = p_atsDetail.cnapsCode;
            }
            if (getBankConfig().getValueAsBool("setCnps999IfEmpty")) {// 配置了为空则置12个9
                if (StringHelper.isNullOrEmpty(tmpRecBankNo)) {
                    tmpRecBankNo = "999999999999";
                }
            } else if (getBankConfig().getValueAsBool("setCnpsEmptyIf999")) {// 配置了12个9置空
                if (StringHelper.hasAnyChar(tmpRecBankNo) && tmpRecBankNo.equals("999999999999")) {
                    tmpRecBankNo = "";
                }
            }
            if (StringHelper.hasAnyChar(p_atsDetail.cnapsName)) {
                tmpRecBankName = p_atsDetail.cnapsName;
            }
        }
        if (!StringHelper.isNullOrEmpty(defautCity)) {
            tmpXElement.addChild(new XElement("RecCityName", defautCity));
        } else {
            tmpXElement.addChild(new XElement("RecCityName", tmpRecCityName));
        }
        tmpXElement.addChild(new XElement("RecBankNo", tmpRecBankNo));
        tmpXElement.addChild(new XElement("RecBankName", tmpRecBankName));
        tmpXElement.addChild(new XElement("CurrType", convertCurToBank(p_atsDetail.payCur)));
        tmpXElement.addChild(new XElement("PayAmt", StringHelper.amountMultiply100(p_atsDetail.payAmount)));
        tmpXElement.addChild(new XElement("UseCode", ""));
        String tmpUseCN = "";
        if (bnkTransCode.equals("PAYPERCOL") || bnkTransCode.equals("PAYPER")) {
            tmpUseCN = getICBCPayUse(p_atsDetail.useType);
            if (StringHelper.isNullOrEmpty(tmpUseCN)) {
                tmpUseCN = p_atsDetail.useType;
            }
        }
        if (StringHelper.isNullOrEmpty(tmpUseCN)) {
            tmpUseCN = p_atsDetail.purpose;
        }
        // UseCn长度不能超过10个字符
        tmpUseCN = StringHelper.subStringByGBKByte(tmpUseCN, 10);
        tmpXElement.addChild(new XElement("UseCN", tmpUseCN));
        tmpXElement.addChild(new XElement("EnSummary", ""));
        // #start 提取摘要、备注，摘要和备注中有一个字段含有对账码，通过提取方法获取对账码-----范天星/2020/01/20
        tmpXElement.addChild(new XElement("PostScript", p_atsDetail.abstractATS));
        String summary = "";
        if (StringHelper.isNullOrEmpty(p_atsDetail.memo)) {
            summary = StringHelper.subStringByGBKByte(p_atsDetail.purpose, 20);
        } else {
            summary = StringHelper.subStringByGBKByte(p_atsDetail.memo, 20);
        }
        tmpXElement.addChild(new XElement("Summary", summary));
        tmpXElement.addChild(new XElement("Ref", p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("Oref", p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("ERPSqn", p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("BusCode", ""));
        tmpXElement.addChild(new XElement("ERPcheckno", ""));
        tmpXElement.addChild(new XElement("CrvouhType", ""));
        tmpXElement.addChild(new XElement("CrvouhName", ""));
        tmpXElement.addChild(new XElement("CrvouhNo", ""));
        if (!("PAYENT".equals(bnkTransCode) && "0.0.1.0".equals(getBankConfig().getMapValueByKey("versionMapping", bnkTransCode)))) {
            tmpXElement.addChild(new XElement("ReqReserved3", ""));
            tmpXElement.addChild(new XElement("ReqReserved4", ""));
        }

        Map<String, String> payDataMap = new HashMap<String, String>();
        boolean enableRefund = getBankConfig().getValueAsBool("enableRefund");
        if (enableRefund) {
            payDataMap.put("ownact", p_atsDetail.payAct);
            payDataMap.put("iseqno", String.valueOf(p_seqIndex));
            payDataMap.put("asknumber", p_atsDetail.askNumber);
            payDataMap.put("amount", p_atsDetail.payAmount);
            payDataMap.put("oppact", p_atsDetail.recAct);
            payDataMap.put("oppactname", p_atsDetail.recName);
            if (StringHelper.hasAnyChar(reqBatchNo)) {
                payDataMap.put("reqbatchno", reqBatchNo);
            }
            savePayDataMapping(payDataMap);
        }
        nodeAnalysis(p_atsDetail.srcXElement, tmpXElement, getCharset());

        return tmpXElement;
    }

    protected XElement convertRecDetailToBankXElement(ReqPayRecDetail p_atsDetail, int p_seqIndex) throws Exception {
        XElement tmpXElement = new XElement("rd", "");

        tmpXElement.addChild(new XElement("iSeqno", String.valueOf(p_seqIndex)));
        tmpXElement.addChild(new XElement("PayAccNo", p_atsDetail.payAct));
        tmpXElement.addChild(new XElement("PayAccNameCN", p_atsDetail.payName));
        tmpXElement.addChild(new XElement("PayAccNameEN", ""));
        String payBranch = p_atsDetail.payBankName;
        if (StringHelper.isNullOrEmpty(payBranch)) {
            payBranch = "中国工商银行";
        }
        tmpXElement.addChild(new XElement("PayBranch", payBranch));
        String clientNum = getBankConfig().getValueAsString("clientNum");
        //ATSES-26821 菲亚特：对公批扣指令提交失败
        if ("1".equals(clientNum) && !"ENTDIS".equals(bnkTransCode)) {
            // 请求获取缴费编号Portno
            String Portno = "";
            // update by zzy JavaDsp调整工行PERDIS取值
            // 先调用QPERINF获取协议编号Portno将赋值给PERDIS中的Portno
            XmlTextWriter xmlWriterFirst = new XmlTextWriter();
            writeCommonHeaderForPortno(xmlWriterFirst);
            Date date = new Date();
            xmlWriterFirst.writeElementString("BeginDate", "19000101", true);// 起始日期
            xmlWriterFirst.writeElementString("EndDate", Format.Date8Format.format(date), true);// 终止日期
            xmlWriterFirst.writeElementString("BeginTime", "", true);// 开始时间
            xmlWriterFirst.writeElementString("EndTime", "", true);// 终止时间
            xmlWriterFirst.writeElementString("RecAccNo", p_atsDetail.recAct, true);// 收费企业账号
            xmlWriterFirst.writeElementString("PayAccNo", p_atsDetail.payAct, true);// 付款账号
            xmlWriterFirst.writeElementString("Portno", "", true);// 缴费编号
            xmlWriterFirst.writeElementString("QueryTag", "0", true);// 查询协议类型 0：签订协议  1：撤销协议
            xmlWriterFirst.writeElementString("NextTag", "", true);// 查询下页标志
            xmlWriterFirst.writeElementString("ReqReserved1", "", true);// 备用
            xmlWriterFirst.writeElementString("ReqReserved2", "", true);// 备用
            xmlWriterFirst.writeEndDocument();
            WriteBankLogLn("提交到银行获取缴费编号Portno的报文：" + xmlWriterFirst.toXmlString());
            //发送给银行

            String[] bankResult = sendToBankForPortno(xmlWriterFirst.toXmlString());
            WriteBankLogStep3("银行返回缴费编号Portno的报文：" + bankResult[1]);
            if (bankResult[0].length() == 0) {
                StringBuilder tmpMsg = new StringBuilder();
                XmlTextReader reader = loadBankRespXmlReader(bankResult[1], tmpMsg);
                if (reader != null) {
                    String respCode = reader.getFirstText("/CMS/eb/pub/RetCode");
                    if ("0".equals(respCode) || "00000".equals(respCode)) {
                        Portno = reader.getFirstText("/CMS/eb/out/rd/Portno");
                    } else if ("B0116".equals(respCode)) {//无记录不等于失败
                        Portno = "";
                    } else {
                        XElement retXml = new XElement("error", "");
                        return retXml;
                    }
                } else {
                    XElement retXml = new XElement("error", "");
                    return retXml;
                }
            } else {
                XElement retXml = new XElement("error", "");
                return retXml;
            }
            tmpXElement.addChild(new XElement("Portno", Portno));
        } //下面的Portno的也需要进行判断

        if ("PERDISCOL".equals(bnkTransCode) || "PERDIS".equals(bnkTransCode)) {
            if ("1".equals(clientNum)) {
            } else {
                if (StringHelper.hasAnyChar(p_atsDetail.authCode)) {
                    tmpXElement.addChild(new XElement("Portno", p_atsDetail.authCode));
                } else {
                    int intLastNum = 30 - p_atsDetail.payAct.length();
                    if (p_atsDetail.payName.length() > intLastNum) {
                        tmpXElement.addChild(new XElement("Portno", p_atsDetail.payAct + p_atsDetail.payName.substring(0, intLastNum)));
                    }
                }
            }

            if (StringHelper.hasAnyChar(p_atsDetail.authAgNum)) {
                tmpXElement.addChild(new XElement("ContractNo", p_atsDetail.authAgNum));
            } else {
                tmpXElement.addChild(new XElement("ContractNo", getBankConfig().getValueAsString("contractNo")));
            }
        }
        tmpXElement.addChild(new XElement("CurrType", convertCurToBank(p_atsDetail.payCur)));
        tmpXElement.addChild(new XElement("PayAmt", StringHelper.amountMultiply100(p_atsDetail.payAmount)));

        String tmpUseCN = "";
        if ("PERDISCOL".equals(bnkTransCode) || "PERDIS".equals(bnkTransCode) || "ENTDIS".equals(bnkTransCode)) {
            tmpUseCN = getICBCPayUse(p_atsDetail.useType);
            if (StringHelper.isNullOrEmpty(tmpUseCN)) {
                tmpUseCN = p_atsDetail.useType;
            }
            if (StringHelper.isNullOrEmpty(tmpUseCN)) {
                tmpUseCN = p_atsDetail.purpose;
            }
            if (StringHelper.isNullOrEmpty(tmpUseCN)) {
                tmpUseCN = p_atsDetail.abstractATS;
            }
            tmpXElement.addChild(new XElement("UseCode", ""));
            tmpXElement.addChild(new XElement("UseCN", tmpUseCN));
        }
        tmpXElement.addChild(new XElement("EnSummary", ""));
        tmpXElement.addChild(new XElement("PostScript", p_atsDetail.abstractATS));
        if (StringHelper.isNullOrEmpty(p_atsDetail.memo)) {
            tmpXElement.addChild(new XElement("Summary", p_atsDetail.purpose));
        } else {
            tmpXElement.addChild(new XElement("Summary", p_atsDetail.memo));
        }
        tmpXElement.addChild(new XElement("Ref", "PERDIS".equals(bnkTransCode) ? "" : p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("Oref", "PERDIS".equals(bnkTransCode) ? "" : p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("ERPSqn", p_atsDetail.askNumber));
        tmpXElement.addChild(new XElement("BusCode", ""));
        tmpXElement.addChild(new XElement("ERPcheckno", ""));
        tmpXElement.addChild(new XElement("CrvouhType", ""));
        tmpXElement.addChild(new XElement("CrvouhName", ""));
        tmpXElement.addChild(new XElement("CrvouhNo", ""));
        tmpXElement.addChild(new XElement("ReqReserved3", ""));
        tmpXElement.addChild(new XElement("ReqReserved4", ""));

        nodeAnalysis(p_atsDetail.srcXElement, tmpXElement, getCharset());

        return tmpXElement;
    }

    public String getICBCPayUse(String p_payUse) throws Exception {
        String tmpValue = getBankConfig().getMapValueByKey("payUseMapping", p_payUse);
        if (StringHelper.isNullOrEmpty(p_payUse)) {
            if (StringHelper.isNullOrEmpty(tmpValue)) {
                return p_payUse;
            } else {
                return tmpValue;
            }
        } else {
            return tmpValue;
        }
    }

    // 根据年月求每个月的月末日期
    public static String dateConvert(Date date) throws ParseException {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int days = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        c.add(Calendar.DAY_OF_MONTH, days - 1);
        Date date2 = c.getTime();
        String monthend = new SimpleDateFormat("yyyyMMdd").format(date2);
        return monthend;
    }

    /*
     *
     *
     *
     * protected Document loadPortFile(String p_transType) throws Exception{
     * String tmpPortFile =
     * FGBiz.dspCenter.rootDirPath+File.separator+"PortFiles"
     * +File.separator+"ICBC02"+File.separator+p_transType+"req.xml";
     *
     * Document tmpDoc = DomHelper.loadXml(tmpPortFile); if(tmpDoc != null){
     * Element rootElement = tmpDoc.getDocumentElement();
     * DomHelper.setSingleElementInnerText(tmpDoc, rootElement, "CIS",
     * bankFront.org); DomHelper.setSingleElementInnerText(tmpDoc, rootElement,
     * "ID", bankFront.keyID); } else{ throw new
     * Exception("配置文件不存在："+tmpPortFile); } return tmpDoc; }
     */

    private static byte tmpByteLt = '<';// "<".getBytes("gbk")[0];
    private static byte tmpHeadCut1 = '\r';// "\\r".getBytes("gbk")[0];
    private static byte tmpHeadCut2 = '\n';// "\\n".getBytes("gbk")[0];

    private boolean isTransferChunked = false;

    public void getContentLength(TcpReceiver p_receiver) throws Exception {
        if (p_receiver.contentLength == -1) {
            for (int i = p_receiver.readHeadStartIndex; i < p_receiver.readedLength; i++) {
                if (p_receiver.recBytes[i] == tmpHeadCut2) {// 是\n
                    int tmpEndCount = i - p_receiver.readHeadStartIndex;
                    if (i > 1 && p_receiver.recBytes[i - 1] == tmpHeadCut1) {// 前一个字符是\r
                        tmpEndCount--;
                    }
                    String tmpHeadKeyValue = new String(p_receiver.recBytes, p_receiver.readHeadStartIndex, tmpEndCount, getCharset());
                    String tmpKey = "";
                    String tmpValue = "";

                    int idx1 = tmpHeadKeyValue.indexOf(":");
                    if (idx1 > 0) {
                        tmpKey = tmpHeadKeyValue.substring(0, idx1).toLowerCase();
                        tmpValue = tmpHeadKeyValue.substring(idx1 + 1).toLowerCase();
                    }

                    if (tmpKey.equals("content-length")) {
                        p_receiver.contentLength = Integer.valueOf(tmpValue.trim());
                    } else if (tmpKey.equals("transfer-encoding")) {
                        WriteBankLogLn(tmpKey + ":" + tmpValue);
                        if ("chunked".equals(tmpValue.trim().toLowerCase())) {
                            isTransferChunked = true;
                        }
                    }
                    p_receiver.readHeadStartIndex = i + 1;

                    if (p_receiver.readedLength > (i + 1) && p_receiver.recBytes[i + 1] == tmpHeadCut2) {
                        p_receiver.contentStartIndex = i + 2;
                        break;
                    } else if (p_receiver.readedLength > (i + 2) && p_receiver.recBytes[i + 2] == tmpHeadCut2) {
                        p_receiver.contentStartIndex = i + 3;
                        break;
                    }
                } else if (p_receiver.recBytes[i] == tmpByteLt) {// 是<
                    p_receiver.contentStartIndex = i;
                    break;
                }
            }

            if (!isTransferChunked && p_receiver.contentStartIndex < 0) {
                String tmpHttpStr = new String(p_receiver.recBytes, 0, p_receiver.readedLength, getCharset());
                if (tmpHttpStr.indexOf('<') > 0) {
                    p_receiver.contentStartIndex = tmpHttpStr.indexOf('<');
                } else if (tmpHttpStr.indexOf("reqData=") > 0) {
                    p_receiver.contentStartIndex = tmpHttpStr.indexOf("reqData=");
                }
            }
        }
    }

    protected String getPayPropByMethod(String payMethod) throws Exception {
        String payProp;
        if (!"".equals(payMethod)) {
            if ("A".equals(payMethod)) {
                payProp = "0";
            } else if ("P".equals(payMethod)) {
                payProp = "1";
            } else if ("R".equals(payMethod)) {
                payProp = "2";
            } else if ("O".equals(payMethod)) {
                payProp = "3";
            } else {
                throw new Exception("付款性质异常");
            }
        } else {
            throw new Exception("付款性质异常");
        }
        return payProp;
    }

    protected void send(String version, String reqData, boolean flag) {
        /*
         * try{
         *
         * }catch (IOException e2){ e2.printStackTrace();
         * WriteBankLogLn("无法读取企业数据层密钥文件"); }catch (Exception e3){
         * e3.printStackTrace(); WriteBankLogLn("无法生成签名"); }
         */
    }

    public void savePayDataMapping(Map<String, String> mapParams) throws Exception {
        Connection conn = FGBiz.getLocalDbConn();
        Statement statement = null;
        try {
            statement = conn.createStatement();
            // 设置 30 秒超时
            statement.setQueryTimeout(30);
            String askNumber = "", reqBatchNo = "", serialNo = "", orderNo = "", fseqno = "", erpsqn = "", iSeqno = "", amount = "", oppAct = "", oppActName = "", ownAct = "";
            if (mapParams.containsKey("askNumber")) {
                askNumber = mapParams.get("askNumber");
            }
            if (mapParams.containsKey("ownact")) {
                ownAct = mapParams.get("ownact");
            }
            if (mapParams.containsKey("iseqno")) {
                iSeqno = mapParams.get("iseqno");
            }
            if (mapParams.containsKey("amount")) {
                amount = mapParams.get("amount");
            }
            if (mapParams.containsKey("oppact")) {
                oppAct = mapParams.get("oppact");
            }
            if (mapParams.containsKey("oppactname")) {
                oppActName = mapParams.get("oppactname");
            }

        /*if (tmpBkReader.read("/CMS/eb/out/rd")) {
            serialNo = tmpBkReader.readedXElement.getSingleText("SerialNo");
            orderNo = tmpBkReader.readedXElement.getSingleText("OrderNo");
            fseqno = tmpBkReader.readedXElement.getSingleText("fSeqno");
            erpsqn = tmpBkReader.readedXElement.getSingleText("ERPSqn");
        }*/

            String strSql = String.format("Insert into ICBCPAYITEM(asknumber,reqbatchno,serialNo,orderno,fseqno,erpsqn,iseqno,amount,oppact,oppactname,ownact) Values('{0}','{1}','{2}','{3}','{4}','{5}','{6}',{7},'{8}','{9}','{10}')", askNumber, reqBatchNo, serialNo, orderNo, fseqno, erpsqn, iSeqno, amount, oppAct, oppActName, ownAct);
            statement.executeUpdate(strSql);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (statement != null) {
                statement.close();
            }
        }
    }

    /**
     * 将分转元
     *
     * @param p_cent
     * @return
     */
    public String amountDivide100(String p_cent) {
        if (StringHelper.isNullOrEmpty(p_cent)) {
            return null;
        }
        return StringHelper.amountDivide100(p_cent);
    }

    /**
     * 处理文档的顶层无效问题
     *
     * @param retStr
     */
    public String[] detailRetSrt(String[] retStr) {
        try {
            if (retStr != null && retStr.length == 2) {
                String returnStr = retStr[1];
                int xmlLength = returnStr.indexOf("</CMS>") + "</CMS>".length() + 1;
                if (returnStr.length() == (xmlLength + 2) && returnStr.endsWith(">")) {
                    retStr[1] = returnStr.substring(0, xmlLength);
                }
            }
        } catch (Exception e) {
        } finally {
            return retStr;
        }
    }

    /**
     * 将MAP转换为post请求串
     *
     * @return
     */
    public String convertMapToStr(Map<String, Object> params) {
        String reqStr = "";
        for (String key : params.keySet()) {
            if (!key.equals("")) {
                if (reqStr.length() > 0) {
                    reqStr += "&";
                }
                reqStr += key + "=" + params.get(key);
            }
        }
        return reqStr;
    }

    public String signWithRSA(ActSetItem actItem, String p_reqStr) throws Exception {
        byte[] encryptBytes = Base64.decode(FileHelper.readFileBytes(actItem.ownKeyStorePath));
        KeyFactory keyfactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyfactory.generatePrivate(new PKCS8EncodedKeySpec(encryptBytes));
        if (privateKey == null) {
            return null;
        }

        byte[] signDigest = SecureUtil.sha256X16(p_reqStr, getCharset());
        byte[] byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft256(privateKey, signDigest));

        return new String(byteSign);
    }

    /**
     * 发送并获取返回
     *
     * @param actItem     商户配置信息
     * @param bizContent  业务JSON
     * @param serviceCode 当前服务
     * @return 响应JOSN
     * @throws Exception 服务器请求异常
     */
    public String sendToBank(String url, String reqData) throws Exception {
        String tmpStrRet = "";
        CloseableHttpClient httpclient = createSSLInsecureClient();
        HttpPost httppost = new HttpPost(url);
        CloseableHttpResponse response = null;
        try {
            StringEntity reqEntity = new StringEntity(reqData, ContentType.create("application/json", getCharset()));
            httppost.setEntity(reqEntity);
            response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                tmpStrRet = EntityUtils.toString(entity, getCharset());
            }
            WriteBankLogStep3(tmpStrRet);
        } catch (IOException ex) {
            ex.printStackTrace();
            throw ex;
        } finally {
            try {
                if (httpclient != null) {
                    httpclient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return tmpStrRet;
    }

    /**
     * @Title: createSSLInsecureClient
     * @Description: 创建发送https请求
     * @return
     * @throws GeneralSecurityException    设定文件
     */
    protected CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
        SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        });
        return HttpClients.custom().setSSLSocketFactory(sslSF).build();
    }

}